﻿using DomenModel;
using Infrastructure.Repositories;
using Model.Repositories;
using Model.Repositories.Interfaces;
using Model.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
    


namespace Infrastructure.Service
{
    public class AdministratorService : IAdministratorService 
    {

        private IUserCrud _dbUsers;
        private ICrud<Role> _dbRole;
        public AdministratorService(IUserCrud DBusers, ICrud<Role> DBRoles)
        {
            _dbUsers = DBusers;
            _dbRole = DBRoles;
        }

        public User GetUser(string loginName)
        {
            var user = _dbUsers.GetByLogin(loginName);
            return user;
        }

        public List<Role> GetRoles()
        {
            var roles = _dbRole.GetCollection();
            return roles;
        }

        public bool DeactivateUser(string loginName)
        {
            _dbUsers.Delete(loginName);
            return true;
        }

        public bool CreateUser(User user)
        {
            var check = _dbUsers.GetByLogin(user.LoginName);
            if (check == null)
            {
                _dbUsers.Save(user);
                return true;
            }
            return false;
        }

        public bool EditUser(User user)
        {
              _dbUsers.Update(user);
              return true;
        }

        public List<User> GetPaginationListOfUsers(int page, int itemsOnPage, string orderUsersBy)
        {
            Expression<Func<User, string>> predicate;

            orderUsersBy = orderUsersBy ?? "UserName";
            bool descending = false;

            string[] st = orderUsersBy.Split(' ');
            if ( st.Length == 2) descending = true; 
            
            switch (st[0])
            {
                case "FirstName":
                    predicate = p => p.FirstName;
                    break;
                case "LastName":
                    predicate = p => p.LastName;
                    break;
                case "Role":
                    predicate = p => p.Role.Name;
                    break;
                case "Email":
                    predicate = p => p.Email;
                    break;
                case "Region":
                    predicate = p => p.Region;
                    break;
                default:
                    predicate = p => p.LoginName;
                    break;
            }
            var list = _dbUsers.GetListForPagination(page, itemsOnPage, predicate, descending);
            return list;
        }

        public List<User> GetPaginationWithFilter(int page, int itemsOnPage, string orderUsersBy, string searchString, string listSelectField, string listSelectCondition)
        {
            Expression<Func<User, string>> predicateSortBy;

            orderUsersBy = orderUsersBy ?? "UserName";
            
            bool descending = false;

            string[] st = orderUsersBy.Split(' ');
            if (st.Length == 2) descending = true;

            switch (st[0])
            {
                case "FirstName":
                    predicateSortBy = p => p.FirstName;
                    break;
                case "LastName":
                    predicateSortBy = p => p.LastName;
                    break;
                case "Role":
                    predicateSortBy = p => p.Role.Name;
                    break;
                case "Email":
                    predicateSortBy = p => p.Email;
                    break;
                case "Region":
                    predicateSortBy = p => p.Region;
                    break;
                default:
                    predicateSortBy = p => p.LoginName;
                    break;
            }

            var filterExpression = Filter(searchString, listSelectField, listSelectCondition);

            var list = _dbUsers.GetListForPaginationWithFilter(page, itemsOnPage, filterExpression, predicateSortBy, descending);
            return list;
        }


        public long GetCountOfUsers()
        {
            var count = _dbUsers.GetCountOfUser();
            return count;
        }

        public long GetCountOfUsers(string searchString, string listSelectField, string listSelectCondition)
        {
            var filterExpression = Filter(searchString, listSelectField, listSelectCondition);
            var count = _dbUsers.GetCountOfUser(filterExpression);
            return count;
        }  

        private Expression<Func<User,bool>> Filter(string searchString, string listSelectField, string listSelectCondition)
        {
            var param = Expression.Parameter(typeof(User), "u");
            MemberExpression prop;
            switch (listSelectField)
            {
                case "User Name":
                    prop = Expression.Property(param, typeof(User).GetProperty("LoginName"));
                    break;

                case "First Name":
                    prop = Expression.Property(param, typeof(User).GetProperty("FirstName"));
                    break;

                case "Last Name":
                    prop = Expression.Property(param, typeof(User).GetProperty("LastName"));
                    break;

                default:
                    prop = Expression.Property(param, typeof(Role).GetProperty("Role.Name"));
                    break;
            }

            string selectedCondition;
            switch (listSelectCondition)
            {
                case "starts with":
                    selectedCondition = "StartsWith";
                    break;

                case "equals":
                    selectedCondition = "Equals";
                    break;

                default:
                    selectedCondition = "Contains";
                    break;
            }

            MethodCallExpression startsWith = Expression.Call(
                prop,
                typeof(String).GetMethod(selectedCondition, new Type[] { typeof(String) }),
                Expression.Constant(searchString)
                );

            return Expression.Lambda<Func<User, bool>>(startsWith, param);

        }

    }

}
